﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.Objects.DataClasses;

namespace mesoBoard.Data.Repositories
{        
    public class ThreadRepository: IThreadRepository
    {
        private mbEntities db;

        public ThreadRepository(mbEntities mbDataContext)
        {
            this.db = mbDataContext;
        }

        public void SyncAllThreads()
        {
            foreach (Thread t in db.Threads.AsEnumerable())
            {
                SyncThread(t.ThreadID);
            }
        }

        public void SyncThread(int ThreadID)
        {
            Thread TheThread = db.Threads.FirstOrDefault(x => x.ThreadID == ThreadID);

            List<Post> posts = db.Posts.Where(x => x.ThreadID == ThreadID).ToList();

            Post LastPost = posts.OrderByDescending(x => x.Date).First() ;
            Post FirstPost = posts.OrderBy(x => x.Date).First();

            int TotalPosts = posts.Count;

            TheThread.LastPostID = LastPost.PostID;
            TheThread.FirstPostID =  FirstPost.PostID;
            TheThread.TotalPosts = TotalPosts;
            TheThread.HasPoll = TheThread.Poll != null;

            TheThread.HasAttachment = db.Attachments.Any(x => x.Post.ThreadID == ThreadID);

            db.SaveChanges();
        }

        public void AddThreadView(int ThreadID, int UserID)
        {
            if (!HasViewed(ThreadID, UserID))
            {
                Thread thread = GetThread(ThreadID);
                db.ThreadViews.AddObject(new ThreadView { UserID = UserID, ThreadID = ThreadID });
                thread.Views++;
                db.SaveChanges();
            }
        }

        public bool HasViewed(int ThreadID, int UserID)
        {
            return db.ThreadViews.FirstOrDefault(x => x.ThreadID == ThreadID && x.UserID == UserID) != null;
        }

        public bool HasNewPost(int ThreadID, int UserID)
        {
            Thread TheThread = db.Threads.FirstOrDefault(x => x.ThreadID == ThreadID);

            Post LastPost = TheThread.LastPost;

            User TheUser = db.Users.FirstOrDefault(x => x.UserID == UserID);

            if (TheUser == null)
                return false;

            if (LastPost.UserID == UserID)
                return false;

            mesoBoard.Data.ThreadViewStamp FoundView = db.ThreadViewStamps.FirstOrDefault(y => y.ThreadID == ThreadID && y.UserID == UserID);
            if (FoundView != null)
                return DateTime.Compare(LastPost.Date, FoundView.Date) > 0;
            else
                return DateTime.Compare(LastPost.Date, TheUser.LastLogoutDate) > 0;
        }

        public Post GetLastPost(int ThreadID)
        {
            return db.Posts.Where(x => x.ThreadID == ThreadID).OrderByDescending(x => x.Date).FirstOrDefault();
        }

        public IEnumerable<Thread> GetThreads(int ForumID)
        {
            return db.Threads.Where(x => x.ForumID == ForumID);
        }

        public Thread GetThread(int ThreadID)
        {
            return db.Threads.First(x => x.ThreadID == ThreadID);
        }

        public IEnumerable<Thread> GetAllThreads(int ForumID)
        {
            return db.Threads.Where(x => x.ForumID == ForumID);
        }

        public IEnumerable<Thread> GetAllThreads()
        {
            return db.Threads.AsEnumerable();
        }

        public int CreateThread(Thread TheThread, Post FirstPost)
        {
            db.Threads.AddObject(TheThread);
            db.SaveChanges();
            db.Posts.AddObject(FirstPost);
            FirstPost.ThreadID = TheThread.ThreadID;
            db.SaveChanges();
            TheThread.FirstPostID = FirstPost.PostID;
            TheThread.LastPostID = FirstPost.PostID;
            TheThread.HasPoll = false;
            TheThread.HasAttachment = TheThread.Posts.Any(x => x.Attachments.Count > 0); ;
            TheThread.TotalPosts = 0;
            db.SaveChanges();
            return TheThread.ThreadID;
        }

        public void CreateThread(Thread theThread)
        {
            db.Threads.AddObject(theThread);
            db.SaveChanges();
        }

        public int CreateThread(Thread TheThread, Post FirstPost, string PollText, string[] PollOptions)
        {
            db.Threads.AddObject(TheThread);
            db.SaveChanges();
            FirstPost.ThreadID = TheThread.ThreadID;
            db.Posts.AddObject(FirstPost);
            db.SaveChanges();

            TheThread.FirstPostID = FirstPost.PostID;
            TheThread.LastPostID = FirstPost.PostID;
            TheThread.HasPoll = true;
            TheThread.HasAttachment = false;
            TheThread.TotalPosts = 0;

            System.Data.Objects.DataClasses.EntityCollection<PollOption> opts = new System.Data.Objects.DataClasses.EntityCollection<PollOption>();
            foreach(string po in PollOptions)
            {
                opts.Add(new PollOption
                {
                    PollID = TheThread.ThreadID,
                    Text = po
                });
            }

            Poll ThePoll = new Poll
            {
                PollOptions = opts,
                Question = PollText,
                PollID = TheThread.ThreadID
            };

            db.Polls.AddObject(ThePoll);
            db.SaveChanges();
            return TheThread.ThreadID;
        }

        public int PostCount(int ThreadID)
        {
            return GetThread(ThreadID).Posts.Count;
        }

        public IEnumerable<Thread> GetPagedThreads(int ForumID, int PageNumber, int PageSize)
        {
            IEnumerable<Thread> Threads = db.Threads.Where(x => x.ForumID == ForumID);
            Threads = Threads.OrderByDescending(x => x.LastPost.Date).OrderByDescending(x => x.Type);
            Threads = Threads.Skip((PageNumber - 1) * PageSize).Take(PageSize);
            return Threads;
        }

        public IEnumerable<Thread> GetGlobalAnnouncements()
        {
            // This function breaks if we do it in one line b/c of the fake navigation property "LastPost"
            IEnumerable<Thread> Threads = db.Threads.Where(x => x.Type == 4);
            Threads = Threads.OrderByDescending(x => x.LastPost.Date);  
            return Threads;
        }

        public void UpdateThread(Thread TheThread)
        {
            if (TheThread.EntityKey == null)
                TheThread.EntityKey = ((Thread)db.GetObjectByKey(new System.Data.EntityKey("mbEntities.Threads", "ThreadID", TheThread.ThreadID))).EntityKey;

            db.Threads.ApplyCurrentValues(TheThread);
            db.SaveChanges();
        }

        public void AddViewed(int ThreadID, int UserID)
        {
            ThreadViewStamp NewView = new ThreadViewStamp
            {
                ThreadID = ThreadID,
                UserID = UserID,
                Date = DateTime.UtcNow
            };
            db.ThreadViewStamps.AddObject(NewView);
            db.SaveChanges();
        }

        public void DeleteViews(int UserID)
        {
            foreach (ThreadViewStamp tvs in db.ThreadViewStamps.Where(x => x.UserID == UserID))
            {
                db.ThreadViewStamps.DeleteObject(tvs);
            }
            db.SaveChanges();
        }

        public IEnumerable<Subscription> GetSubscriptions(int ThreadID)
        {
            return db.Subscriptions.Where(x => x.ThreadID == ThreadID);
        }

        public void CreateSubscription(Subscription s)
        {
            db.Subscriptions.AddObject(s);
            db.SaveChanges();
        }

        public void DeleteSubscription(int UserID, int ThreadID)
        {
            db.Subscriptions.DeleteObject(db.Subscriptions.FirstOrDefault(x=>x.UserID == UserID && x.ThreadID == ThreadID));
            db.SaveChanges();
        }

        public bool IsSubscribed(int UserID, int ThreadID)
        {
            return db.Subscriptions.FirstOrDefault(x => x.ThreadID == ThreadID && x.UserID == UserID) == null ? false : true;
        }

        public void DeleteThread(int ThreadID)
        {
            db.Threads.DeleteObject(GetThread(ThreadID));
            db.SaveChanges();
        }

        public int TotalThreads()
        {
            return db.Threads.Count();
        }

        public void SubmitChanges()
        {
            db.SaveChanges();
        }

        public ThreadViewStamp GetThreadViewStamp(int UserID, int ThreadID)
        {
            return db.ThreadViewStamps.FirstOrDefault(x => x.UserID == UserID && x.ThreadID == ThreadID);
        }

        public void DeleteThreadViewStamp(int UserID, int ThreadID)
        {
            ThreadViewStamp viewStamp = db.ThreadViewStamps.FirstOrDefault(x => x.UserID == UserID && x.ThreadID == ThreadID);

            if(viewStamp != null)
            {
                db.ThreadViewStamps.DeleteObject(viewStamp);
                db.SaveChanges();
            }
        }
    }
}
